package MF1DSolver;

import java.util.ArrayList;
import java.util.Iterator;

import jmeshless.NewOkCancelDialog;

import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

import FEMShapeFunction1D.FEMShapeFunction1D1;
import Integration.GaussQuadrature;
import Integration.IFunction1D;
import MeshlessShapeFunctions.JGaussian;
import MeshlessShapeFunctions.JMeshlessInterpolationFunction1DCoupled2;
import MeshlessShapeFunctions.JStKernel;
import MeshlessShapeFunctions.Particle;

public class enrichedFEMElement {
	protected double left;
	protected double right;
	protected FEMShapeFunction1D1 lFEM;
	protected FEMShapeFunction1D1 rFEM;
	protected int lFEMPos;
	protected int rFEMPos;
	protected ArrayList<JMeshlessInterpolationFunction1DCoupled2> mfList;
	protected IFunction1D p;
	protected IFunction1D q;
	protected IFunction1D w;
	protected IFunction1D f;
	
	public enrichedFEMElement(int numberOfMFParticles,FEMShapeFunction1D1 lFEM,FEMShapeFunction1D1 rFEM,int lEFMPos,int rEFMPos){
		this.lFEM = lFEM;
		this.rFEM = rFEM;
		this.lFEMPos = lEFMPos;
		this.rFEMPos = rEFMPos;
		this.left = this.lFEM.getXi();
		this.right = this.rFEM.getXi();
		
//		right = 1.0;
//		left = 0.0;
		
		double h = (right-left)/(double)numberOfMFParticles;
		
		ArrayList<Particle> ls1D = new ArrayList<Particle>();
        for (int i = 1; i <numberOfMFParticles; i++) {
            ls1D.add(new Particle(left+h*i, 0, i));
        }
        ArrayList<FEMShapeFunction1D1> fem = new ArrayList<FEMShapeFunction1D1>();
        fem.add(lFEM);
        fem.add(rFEM);
        mfList = new ArrayList<JMeshlessInterpolationFunction1DCoupled2>();
        for (int i = 0; i < ls1D.size(); i++) {
        	double rho = 3.5*h;
        	ls1D.get(i).setRho(rho);
            JMeshlessInterpolationFunction1DCoupled2 f = new JMeshlessInterpolationFunction1DCoupled2(2, ls1D.get(i).getX(), rho, new JGaussian(rho), fem);
            f.setNodeList(ls1D);
            mfList.add(f);
        }
        
        XYSeries series1 = new XYSeries("1", true, true);
        XYSeriesCollection col  = new XYSeriesCollection();
        h = 0.001;
        for (Iterator<JMeshlessInterpolationFunction1DCoupled2> iterator = mfList.iterator(); iterator.hasNext();) {
			JMeshlessInterpolationFunction1DCoupled2 f = iterator.next();
			for ( double x = 0.0 ; x <= right + h; x+=h) {
	            double tmp = f.calculate(x);
	            series1.add(x,tmp);
	        }
			col.addSeries(series1);
		}
        
        NewOkCancelDialog dialog = new NewOkCancelDialog(null, false, col);
        dialog.setLocationRelativeTo(null);
        dialog.setVisible(true);
	}

	public double[][] generateMatrix(){
		double[][] res = new double[mfList.size()][mfList.size()];
		elementMatrixGeneratorMF1DEnriched gen = new elementMatrixGeneratorMF1DEnriched();
		gen.left = this.left;
		gen.right = this.right;
			for (int i = 0; i < mfList.size(); i++) {
				JMeshlessInterpolationFunction1DCoupled2 phi1  = mfList.get(i);
				gen.setPhi1(phi1);
				for (int j = 0; j < mfList.size(); j++) {
					JMeshlessInterpolationFunction1DCoupled2 phi2  = mfList.get(j);
					gen.setPhi2(phi2);
					gen.update();
					res[i][j] = gen.generateAll(p, q, w);
				}
			}
		
		return res;
	}
	
	public double[] generateFVector(){
		double[] res = new double[mfList.size()];
		elementMatrixGeneratorMF1DEnriched gen = new elementMatrixGeneratorMF1DEnriched();
		gen.left = this.left;
		gen.right = this.right;
			for (int i = 0; i < mfList.size(); i++) {
				JMeshlessInterpolationFunction1DCoupled2 phi1  = mfList.get(i);
				gen.setPhi1(phi1);
				res[i] = gen.generateFeElement(f);
			}
		
		return res;
	}
	
	public double[] generateMFFEMLeft(){
		double[] res = new double[mfList.size()];
		GaussQuadrature gau = new GaussQuadrature(50);
		
		for (int i = 0; i < res.length; i++) {
			final JMeshlessInterpolationFunction1DCoupled2 phi = mfList.get(i);
			res[i] = gau.justGauss(left, right, new IFunction1D() {
				
				@Override
				public double calculateDerivaty(double x) {
					// TODO Auto-generated method stub
					return 0;
				}
				
				@Override
				public double calculate(double x) {
					double p1 = phi.calculate(x);
                	double p1p = phi.calculateDerivaty(x);
                	double p2 = lFEM.calculate(x);
                	double p2p = lFEM.calculateDerivaty(x);
                	
                    return p1*p2*q.calculate(x) + p1p*p2p*p.calculate(x) + p2p*p1*w.calculate(x);
				}
			});
		}
		
		return res;
	}
	
	public double[] generateFEMMFLeft(){
		double[] res = new double[mfList.size()];
		GaussQuadrature gau = new GaussQuadrature(50);
		
		for (int i = 0; i < res.length; i++) {
			final JMeshlessInterpolationFunction1DCoupled2 phi = mfList.get(i);
			res[i] = gau.justGauss(left, right, new IFunction1D() {
				
				@Override
				public double calculateDerivaty(double x) {
					// TODO Auto-generated method stub
					return 0;
				}
				
				@Override
				public double calculate(double x) {
					double p1 = phi.calculate(x);
                	double p1p = phi.calculateDerivaty(x);
                	double p2 = lFEM.calculate(x);
                	double p2p = lFEM.calculateDerivaty(x);
                	
                    return p1*p2*q.calculate(x) + p1p*p2p*p.calculate(x) + p2*p1p*w.calculate(x);
				}
			});
		}
		
		return res;
	}
	
	public double[] generateMFFEMRight(){
		double[] res = new double[mfList.size()];
		GaussQuadrature gau = new GaussQuadrature(50);
		
		for (int i = 0; i < res.length; i++) {
			final JMeshlessInterpolationFunction1DCoupled2 phi = mfList.get(i);
			res[i] = gau.justGauss(left, right, new IFunction1D() {
				
				@Override
				public double calculateDerivaty(double x) {
					// TODO Auto-generated method stub
					return 0;
				}
				
				@Override
				public double calculate(double x) {
					double p1 = phi.calculate(x);
                	double p1p = phi.calculateDerivaty(x);
                	double p2 = rFEM.calculate(x);
                	double p2p = rFEM.calculateDerivaty(x);
                	
                    return p1*p2*q.calculate(x) + p1p*p2p*p.calculate(x) + p2p*p1*w.calculate(x);
				}
			});
		}
		
		return res;
	}
	
	public double[] generateFEMMFRight(){
		double[] res = new double[mfList.size()];
		GaussQuadrature gau = new GaussQuadrature(50);
		
		for (int i = 0; i < res.length; i++) {
			final JMeshlessInterpolationFunction1DCoupled2 phi = mfList.get(i);
			res[i] = gau.justGauss(left, right, new IFunction1D() {
				
				@Override
				public double calculateDerivaty(double x) {
					// TODO Auto-generated method stub
					return 0;
				}
				
				@Override
				public double calculate(double x) {
					double p1 = phi.calculate(x);
                	double p1p = phi.calculateDerivaty(x);
                	double p2 = rFEM.calculate(x);
                	double p2p = rFEM.calculateDerivaty(x);
                	
                    return p1*p2*q.calculate(x) + p1p*p2p*p.calculate(x) + p2*p1p*w.calculate(x);
				}
			});
		}
		
		return res;
	}
	
	public void setF(IFunction1D f) {
		this.f = f;
	}
	
	public void setP(IFunction1D p) {
		this.p = p;
	}
	
	public void setQ(IFunction1D q) {
		this.q = q;
	}
	
	public void setW(IFunction1D w) {
		this.w = w;
	}
	
	public int getlFEMPos() {
		return lFEMPos;
	}
	
	public int getrFEMPos() {
		return rFEMPos;
	}
}
